package com.xiaoluo.web;

import com.jcraft.jsch.*;
import com.xiaoluo.cd.entity.base.Servers;
import com.xiaoluo.common.enums.ServerTypeEnum;
import com.xiaoluo.common.shell.Command;
import com.xiaoluo.common.shell.WebOutputStream;
import com.xiaoluo.common.utils.ApplicationContextUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.websocket.*;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.List;

/**
 * Project : XL-CD
 * Package : com.xiaoluo.web
 * Created by Willian.
 * Date  : 2016/3/17 15:19.
 */
@ServerEndpoint("/openShell")
public class ShellServlet{
    private final static Logger logger = LoggerFactory.getLogger(IndexController.class);
    private final static String USER_NAME = "root";
    private final static String PASS_WORD = "root";
    private static int onlineCount = 0;

    //session
    private Session session;
    private JSch jsch;
    private Channel channel;
    private PipedInputStream inputStream = new PipedInputStream();
    private PipedOutputStream outputStream = new PipedOutputStream();
    private WebOutputStream shellOutputStream = null;


    /**
     * 连接建立成功调用的方法
     * @param session  可选的参数。session为与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    @OnOpen
    public void onOpen(Session session){
        System.out.println("有新连接加入！当前在线人数为" + getOnlineCount());
        addOnlineCount();//在线数加1

        this.session = session;
        shellOutputStream = new WebOutputStream(session);

        String type = session.getRequestParameterMap().get("type").get(0);
        String ip = session.getRequestParameterMap().get("ip").get(0);
        List<Servers> serverses = ApplicationContextUtils.serverService.queryByType(ServerTypeEnum.valueOf(type).getValue());
        /**
         * 获取跳板机信息
         */
        if(serverses != null && serverses.size() >0){
            Servers server = serverses.get(0);

            jsch = new JSch();
            jsch.setLogger(new MyLogger());
            String host = server.getIp();
            String user = server.getUserName();

            try {
                //连接跳板机
                com.jcraft.jsch.Session sshSession = jsch.getSession(user, host, server.getPort());
                String passwd = server.getPassWord();
                sshSession.setPassword(passwd);

                UserInfo ui = new MyUserInfo(){
                    public void showMessage(String message){
                        System.out.println("Welcome...");;
                    }
                    public boolean promptYesNo(String message){
                        Object[] options={ "yes", "no" };
                        return true;
                    }
                };
                //与跳板机建立连接
                sshSession.setUserInfo(ui);
                sshSession.connect(30000);   // making a connection with timeout.
                channel = sshSession.openChannel("shell");
                inputStream.connect(outputStream);
                channel.setInputStream(inputStream);
                channel.setOutputStream(shellOutputStream);
                channel.connect(3 * 1000);
                //登录目标机器
                Command.login(ip,USER_NAME,PASS_WORD,outputStream);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(){
        subOnlineCount();           //在线数减1
        if(session != null && session.isOpen()){
            try {
                session.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        logger.info("有一连接关闭！当前在线人数为" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     * @param message 客户端发送过来的消息
     * @param session 可选的参数
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        logger.info("run {}.",message);

        try {
            Command.exec(message,outputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    /**
     * 发生错误时调用
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error){
        error.printStackTrace();
    }


    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        ShellServlet.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        ShellServlet.onlineCount--;
    }

    public static class MyLogger implements com.jcraft.jsch.Logger {
        static java.util.Hashtable name=new java.util.Hashtable();
        static{
            name.put(new Integer(DEBUG), "DEBUG: ");
            name.put(new Integer(INFO), "INFO: ");
            name.put(new Integer(WARN), "WARN: ");
            name.put(new Integer(ERROR), "ERROR: ");
            name.put(new Integer(FATAL), "FATAL: ");
        }
        public boolean isEnabled(int level){
            return true;
        }
        public void log(int level, String message){
            System.err.print(name.get(new Integer(level)));
            System.err.println(message);
        }
    }

    public static abstract class MyUserInfo
            implements UserInfo, UIKeyboardInteractive {
        public String getPassword() {
            return null;
        }

        public boolean promptYesNo(String str) {
            return false;
        }

        public String getPassphrase() {
            return null;
        }

        public boolean promptPassphrase(String message) {
            return false;
        }

        public boolean promptPassword(String message) {
            return false;
        }

        public void showMessage(String message) {
        }

        public String[] promptKeyboardInteractive(String destination,
                                                  String name,
                                                  String instruction,
                                                  String[] prompt,
                                                  boolean[] echo) {
            return null;
        }
    }
}
